#include <iostream>
using std::string;

#include "dir.hxx"

#ifdef __cplusplus
extern "C"{
#endif

// C code...
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>           /* Definition of AT_* constants */
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>

//检查目录/文件是否存在
// path ： 需要判断的路径
// 返回值：
//   存在则返回0
int IsPathExist(const char* path)
{
    return !access(path, F_OK);
}

//获取程序所在目录
// buff ： 需要接收的buffer
// maxWrite ： 需要接收的buffer的最大长度
// 返回值：
//   参数错误时时返回-1；成功时返回路径长度（限制于maxWrite）
int getCurrentPath(char * buff, int maxWrite)
{
    int min;
    int ret;

    if(buff == NULL)
    {
        return -1;
    }
    min = maxWrite > MAX_DIR_LEN ? MAX_DIR_LEN : maxWrite;
    ret = readlink("/proc/self/exe", buff, min);
    if(ret != -1)
    {
        buff[ret] = '\0';
    }

    return ret;
}

// 删除文件
void delFile(const char* filename)
{
    if (remove(filename) == 0)
    {
        //printf("Removed %s.", filename);
    }
    else
    {
        perror("remove");
    }
}


#ifdef __cplusplus
}
#endif

#define BYTES_OF_CURRENT_FOLDER 4096



//构造函数
CheckSpace::CheckSpace(const char * filepath) {
    this -> m_TBytes = 0;
    this -> m_GBytes = 0;
    this -> m_MBytes = 0;
    this -> m_KBytes = 0;
    this -> m_Bytes = 0;

    m_FilePath[0] = 0;
    if(filepath)
    {
        strcpy(this -> m_FilePath, filepath);
        AddBytes(BYTES_OF_CURRENT_FOLDER); //加上该目录本身占据的4096
    }
}

//获取各项属性
int CheckSpace::GetTB(void) {
    return this -> m_TBytes;
}
int CheckSpace::GetGB(void) {
    return this -> m_GBytes;
}
int CheckSpace::GetMB(void) {
    return this -> m_MBytes;
}
int CheckSpace::GetKB(void) {
    return this -> m_KBytes;
}
int CheckSpace::GetBytes(void) {
    return this -> m_Bytes;
}

//展示内容
void CheckSpace::Display() {
    if(m_FilePath[0] != 0)
    {
        printf("查询目录路径 %s\n", m_FilePath);
    }
    printf("占用空间 %dTB %dGB %dMB %dKB %dByte(s)\n", m_TBytes, m_GBytes, m_MBytes, m_KBytes, m_Bytes);
}
void CheckSpace::DoCheck(void) {
    char buf[256];
    getcwd(buf, sizeof(buf));
    this -> _Check(m_FilePath);
    chdir(buf);
}

//查看某目录所占空间大小（不含该目录本身的4096Byte）
void CheckSpace::_Check(const char * dir) {
    DIR * dp;
    struct dirent * entry;
    struct stat statbuf;

    if ((dp = opendir(dir)) == NULL) {
        fprintf(stderr, "Cannot open dir: %s\n", dir);
        exit(0);
    }

    chdir(dir);

    while ((entry = readdir(dp)) != NULL) {
        lstat(entry -> d_name, & statbuf);
        if (S_ISDIR(statbuf.st_mode)) {
            if (strcmp(".", entry -> d_name) == 0 ||
                    strcmp("..", entry -> d_name) == 0) {
                continue;
            }

            AddBytes(statbuf.st_size);
            _Check(entry -> d_name);
        } else {
            AddBytes(statbuf.st_size);
        }
    }

    chdir("..");
    closedir(dp);
}

//Byte数量增加（自动进位）
void CheckSpace::AddBytes(int bytes) {
    m_Bytes += bytes;
    while (m_Bytes >= 1024) {
        m_Bytes -= 1024;
        m_KBytes++;
    }
    while (m_KBytes >= 1024) {
        m_KBytes -= 1024;
        m_MBytes++;
    }
    while (m_MBytes >= 1024) {
        m_MBytes -= 1024;
        m_GBytes++;
    }
    while (m_GBytes >= 1024) {
        m_GBytes -= 1024;
        m_TBytes++;
    }
}

//KByte数量增加（自动进位）
void CheckSpace::AddKBytes(int kbytes) {
    m_KBytes += kbytes;
    while (m_KBytes >= 1024) {
        m_KBytes -= 1024;
        m_MBytes++;
    }
    while (m_MBytes >= 1024) {
        m_MBytes -= 1024;
        m_GBytes++;
    }
    while (m_GBytes >= 1024) {
        m_GBytes -= 1024;
        m_TBytes++;
    }
}
//KByte数量增加（自动进位）
void CheckSpace::AddMBytes(int mbytes) {
    m_MBytes += mbytes;
    while (m_MBytes >= 1024) {
        m_MBytes -= 1024;
        m_GBytes++;
    }
    while (m_GBytes >= 1024) {
        m_GBytes -= 1024;
        m_TBytes++;
    }
}
//KByte数量增加（自动进位）
void CheckSpace::AddGBytes(int gbytes) {
    m_GBytes += gbytes;
    while (m_GBytes >= 1024) {
        m_GBytes -= 1024;
        m_TBytes++;
    }
}

// 判断容量是否超过指定MB
int CheckSpace::isBiggerThanXMB(int bytes_for_mb, int bytes_for_kb)
{
    CheckSpace cs_cal;
    int i;

    for(i = 0; i < bytes_for_mb; i++)
    {
        cs_cal.AddMBytes(1);
    }
    for(i = 0; i < bytes_for_kb; i++)
    {
        cs_cal.AddKBytes(1);
    }

    if(this->GetTB() > cs_cal.GetTB())
    {
        //printf("TB\n");
        return 1;
    }
    if(this->GetGB() > cs_cal.GetGB())
    {
        //printf("TB\n");
        return 1;
    }
    if(this->GetMB() > cs_cal.GetMB())
    {
        //printf("MB\n");
        return 1;
    }
    if(this->GetKB() > cs_cal.GetKB())
    {
        return 1;
    }

    return 0;
}

#if 0
/* 顺序打印指定目录下文件 */
int listDir(const char *dir)
{
    struct dirent **namelist;
    int n, m;
    n = scandir(dir, &namelist, NULL, alphasort);
    if (n < 0)
        perror("scandir error");
    else
    {
        for (m = 0; m < n; ++m)
        {
            //printf("%s\n", namelist[m]->d_name);
            free(namelist[m]);
        }
        free(namelist);
    }
}
#endif

/* 如果超出大小(MB)，则删除其中的第一个文件 */
int rmOldestFileIfExceedSize(const char *dir, const char * dev_id, int max_mb)
{
    struct dirent **namelist;
    //char del_file_name[256];
    string del_file_name;
    int n, m;
    int i;

    CheckSpace cs(dir);
    CheckSpace cs_cal(NULL);

    cs.DoCheck();

    for(i = 0; i < max_mb; i++)
    {
        cs_cal.AddMBytes(1024 * 1024);
    }
    //cs.Display();
    //cs_cal.Display();

    if(cs.GetTB() > cs_cal.GetTB())
    {
        //printf("TB\n");
        goto del;
    }
    if(cs.GetGB() > cs_cal.GetGB())
    {
        //printf("TB\n");
        goto del;
    }
    if(cs.GetMB() > cs_cal.GetMB())
    {
        //printf("MB\n");
        goto del;
    }

    //printf("Save OK\n");

    return 0;
del:
    del_file_name = string("");

    n = scandir(dir, &namelist, NULL, alphasort);
    if (n < 0)
    {
        perror("scandir error");
    }
    else
    {
        for (m = 0; m < n; ++m)
        {
            if(string(namelist[m]->d_name) == "." || string(namelist[m]->d_name) == ".." )
            {
                //printf("---%s\n", namelist[m]->d_name);
            } else
            {
                if( del_file_name.length() == 0)
                {
                    del_file_name  = namelist[m]->d_name;
                }
            }
            free(namelist[m]);
        }
        free(namelist);
    }
    if( del_file_name.length() != 0)
    {
        del_file_name = string(dir) + string(del_file_name);
        //printf("Deleting file : %s\n", del_file_name.c_str());
        delFile(del_file_name.c_str());
        return 1;
    }
    return 0;
}


/*

int du_dir(const char* dir)
{
    CheckSpace cs = CheckSpace(dir);
    cs.DoCheck();
    cs.Display();
    //printf("Done.\n");
    return 0;
}

*/
